﻿using System;
using Mono.Cecil.Metadata;
using Mono.Collections.Generic;

namespace Mono.Cecil
{
	// Token: 0x02000089 RID: 137
	public class DefaultMetadataImporter : IMetadataImporter
	{
		// Token: 0x06000526 RID: 1318 RVA: 0x00003DEB File Offset: 0x00001FEB
		public DefaultMetadataImporter(ModuleDefinition module)
		{
			Mixin.CheckModule(module);
			this.module = module;
		}

		// Token: 0x06000527 RID: 1319 RVA: 0x0001DC60 File Offset: 0x0001BE60
		private TypeReference ImportType(TypeReference type, ImportGenericContext context)
		{
			bool flag = type.IsTypeSpecification();
			TypeReference result;
			if (flag)
			{
				result = this.ImportTypeSpecification(type, context);
			}
			else
			{
				TypeReference typeReference = new TypeReference(type.Namespace, type.Name, this.module, this.ImportScope(type), type.IsValueType);
				MetadataSystem.TryProcessPrimitiveTypeReference(typeReference);
				bool isNested = type.IsNested;
				if (isNested)
				{
					typeReference.DeclaringType = this.ImportType(type.DeclaringType, context);
				}
				bool hasGenericParameters = type.HasGenericParameters;
				if (hasGenericParameters)
				{
					DefaultMetadataImporter.ImportGenericParameters(typeReference, type);
				}
				result = typeReference;
			}
			return result;
		}

		// Token: 0x06000528 RID: 1320 RVA: 0x0001DCE8 File Offset: 0x0001BEE8
		protected virtual IMetadataScope ImportScope(TypeReference type)
		{
			return this.ImportScope(type.Scope);
		}

		// Token: 0x06000529 RID: 1321 RVA: 0x0001DD08 File Offset: 0x0001BF08
		protected IMetadataScope ImportScope(IMetadataScope scope)
		{
			IMetadataScope result;
			switch (scope.MetadataScopeType)
			{
			case MetadataScopeType.AssemblyNameReference:
				result = this.ImportReference((AssemblyNameReference)scope);
				break;
			case MetadataScopeType.ModuleReference:
				throw new NotImplementedException();
			case MetadataScopeType.ModuleDefinition:
			{
				bool flag = scope == this.module;
				if (flag)
				{
					result = scope;
				}
				else
				{
					result = this.ImportReference(((ModuleDefinition)scope).Assembly.Name);
				}
				break;
			}
			default:
				throw new NotSupportedException();
			}
			return result;
		}

		// Token: 0x0600052A RID: 1322 RVA: 0x0001DD7C File Offset: 0x0001BF7C
		public virtual AssemblyNameReference ImportReference(AssemblyNameReference name)
		{
			Mixin.CheckName(name);
			AssemblyNameReference assemblyNameReference;
			bool flag = this.module.TryGetAssemblyNameReference(name, out assemblyNameReference);
			AssemblyNameReference result;
			if (flag)
			{
				result = assemblyNameReference;
			}
			else
			{
				assemblyNameReference = new AssemblyNameReference(name.Name, name.Version)
				{
					Culture = name.Culture,
					HashAlgorithm = name.HashAlgorithm,
					IsRetargetable = name.IsRetargetable,
					IsWindowsRuntime = name.IsWindowsRuntime
				};
				byte[] array = (!name.PublicKeyToken.IsNullOrEmpty<byte>()) ? new byte[name.PublicKeyToken.Length] : Empty<byte>.Array;
				bool flag2 = array.Length != 0;
				if (flag2)
				{
					Buffer.BlockCopy(name.PublicKeyToken, 0, array, 0, array.Length);
				}
				assemblyNameReference.PublicKeyToken = array;
				this.module.AssemblyReferences.Add(assemblyNameReference);
				result = assemblyNameReference;
			}
			return result;
		}

		// Token: 0x0600052B RID: 1323 RVA: 0x0001DE50 File Offset: 0x0001C050
		private static void ImportGenericParameters(IGenericParameterProvider imported, IGenericParameterProvider original)
		{
			Collection<GenericParameter> genericParameters = original.GenericParameters;
			Collection<GenericParameter> genericParameters2 = imported.GenericParameters;
			for (int i = 0; i < genericParameters.Count; i++)
			{
				genericParameters2.Add(new GenericParameter(genericParameters[i].Name, imported));
			}
		}

		// Token: 0x0600052C RID: 1324 RVA: 0x0001DE9C File Offset: 0x0001C09C
		private TypeReference ImportTypeSpecification(TypeReference type, ImportGenericContext context)
		{
			ElementType etype = type.etype;
			ElementType elementType = etype;
			switch (elementType)
			{
			case ElementType.Ptr:
			{
				PointerType pointerType = (PointerType)type;
				return new PointerType(this.ImportType(pointerType.ElementType, context));
			}
			case ElementType.ByRef:
			{
				ByReferenceType byReferenceType = (ByReferenceType)type;
				return new ByReferenceType(this.ImportType(byReferenceType.ElementType, context));
			}
			case ElementType.ValueType:
			case ElementType.Class:
			case ElementType.TypedByRef:
			case (ElementType)23:
			case ElementType.I:
			case ElementType.U:
			case (ElementType)26:
			case ElementType.Object:
				break;
			case ElementType.Var:
			{
				GenericParameter genericParameter = (GenericParameter)type;
				bool flag = genericParameter.DeclaringType == null;
				if (flag)
				{
					throw new InvalidOperationException();
				}
				return context.TypeParameter(genericParameter.DeclaringType.FullName, genericParameter.Position);
			}
			case ElementType.Array:
			{
				ArrayType arrayType = (ArrayType)type;
				ArrayType arrayType2 = new ArrayType(this.ImportType(arrayType.ElementType, context));
				bool isVector = arrayType.IsVector;
				if (isVector)
				{
					return arrayType2;
				}
				Collection<ArrayDimension> dimensions = arrayType.Dimensions;
				Collection<ArrayDimension> dimensions2 = arrayType2.Dimensions;
				dimensions2.Clear();
				for (int i = 0; i < dimensions.Count; i++)
				{
					ArrayDimension arrayDimension = dimensions[i];
					dimensions2.Add(new ArrayDimension(arrayDimension.LowerBound, arrayDimension.UpperBound));
				}
				return arrayType2;
			}
			case ElementType.GenericInst:
			{
				GenericInstanceType genericInstanceType = (GenericInstanceType)type;
				TypeReference type2 = this.ImportType(genericInstanceType.ElementType, context);
				Collection<TypeReference> genericArguments = genericInstanceType.GenericArguments;
				GenericInstanceType genericInstanceType2 = new GenericInstanceType(type2, genericArguments.Count);
				Collection<TypeReference> genericArguments2 = genericInstanceType2.GenericArguments;
				for (int j = 0; j < genericArguments.Count; j++)
				{
					genericArguments2.Add(this.ImportType(genericArguments[j], context));
				}
				return genericInstanceType2;
			}
			case ElementType.FnPtr:
			{
				FunctionPointerType functionPointerType = (FunctionPointerType)type;
				FunctionPointerType functionPointerType2 = new FunctionPointerType
				{
					HasThis = functionPointerType.HasThis,
					ExplicitThis = functionPointerType.ExplicitThis,
					CallingConvention = functionPointerType.CallingConvention,
					ReturnType = this.ImportType(functionPointerType.ReturnType, context)
				};
				bool flag2 = !functionPointerType.HasParameters;
				if (flag2)
				{
					return functionPointerType2;
				}
				for (int k = 0; k < functionPointerType.Parameters.Count; k++)
				{
					functionPointerType2.Parameters.Add(new ParameterDefinition(this.ImportType(functionPointerType.Parameters[k].ParameterType, context)));
				}
				return functionPointerType2;
			}
			case ElementType.SzArray:
			{
				ArrayType arrayType3 = (ArrayType)type;
				return new ArrayType(this.ImportType(arrayType3.ElementType, context));
			}
			case ElementType.MVar:
			{
				GenericParameter genericParameter2 = (GenericParameter)type;
				bool flag3 = genericParameter2.DeclaringMethod == null;
				if (flag3)
				{
					throw new InvalidOperationException();
				}
				return context.MethodParameter(context.NormalizeMethodName(genericParameter2.DeclaringMethod), genericParameter2.Position);
			}
			case ElementType.CModReqD:
			{
				RequiredModifierType requiredModifierType = (RequiredModifierType)type;
				return new RequiredModifierType(this.ImportType(requiredModifierType.ModifierType, context), this.ImportType(requiredModifierType.ElementType, context));
			}
			case ElementType.CModOpt:
			{
				OptionalModifierType optionalModifierType = (OptionalModifierType)type;
				return new OptionalModifierType(this.ImportType(optionalModifierType.ModifierType, context), this.ImportType(optionalModifierType.ElementType, context));
			}
			default:
				if (elementType == ElementType.Sentinel)
				{
					SentinelType sentinelType = (SentinelType)type;
					return new SentinelType(this.ImportType(sentinelType.ElementType, context));
				}
				if (elementType == ElementType.Pinned)
				{
					PinnedType pinnedType = (PinnedType)type;
					return new PinnedType(this.ImportType(pinnedType.ElementType, context));
				}
				break;
			}
			throw new NotSupportedException(type.etype.ToString());
		}

		// Token: 0x0600052D RID: 1325 RVA: 0x0001E284 File Offset: 0x0001C484
		private FieldReference ImportField(FieldReference field, ImportGenericContext context)
		{
			TypeReference typeReference = this.ImportType(field.DeclaringType, context);
			context.Push(typeReference);
			FieldReference result;
			try
			{
				result = new FieldReference
				{
					Name = field.Name,
					DeclaringType = typeReference,
					FieldType = this.ImportType(field.FieldType, context)
				};
			}
			finally
			{
				context.Pop();
			}
			return result;
		}

		// Token: 0x0600052E RID: 1326 RVA: 0x0001E2F8 File Offset: 0x0001C4F8
		private MethodReference ImportMethod(MethodReference method, ImportGenericContext context)
		{
			bool isGenericInstance = method.IsGenericInstance;
			MethodReference result;
			if (isGenericInstance)
			{
				result = this.ImportMethodSpecification(method, context);
			}
			else
			{
				TypeReference declaringType = this.ImportType(method.DeclaringType, context);
				MethodReference methodReference = new MethodReference
				{
					Name = method.Name,
					HasThis = method.HasThis,
					ExplicitThis = method.ExplicitThis,
					DeclaringType = declaringType,
					CallingConvention = method.CallingConvention
				};
				bool hasGenericParameters = method.HasGenericParameters;
				if (hasGenericParameters)
				{
					DefaultMetadataImporter.ImportGenericParameters(methodReference, method);
				}
				context.Push(methodReference);
				try
				{
					methodReference.ReturnType = this.ImportType(method.ReturnType, context);
					bool flag = !method.HasParameters;
					if (flag)
					{
						result = methodReference;
					}
					else
					{
						Collection<ParameterDefinition> parameters = method.Parameters;
						ParameterDefinitionCollection parameterDefinitionCollection = methodReference.parameters = new ParameterDefinitionCollection(methodReference, parameters.Count);
						for (int i = 0; i < parameters.Count; i++)
						{
							parameterDefinitionCollection.Add(new ParameterDefinition(this.ImportType(parameters[i].ParameterType, context)));
						}
						result = methodReference;
					}
				}
				finally
				{
					context.Pop();
				}
			}
			return result;
		}

		// Token: 0x0600052F RID: 1327 RVA: 0x0001E434 File Offset: 0x0001C634
		private MethodSpecification ImportMethodSpecification(MethodReference method, ImportGenericContext context)
		{
			bool flag = !method.IsGenericInstance;
			if (flag)
			{
				throw new NotSupportedException();
			}
			GenericInstanceMethod genericInstanceMethod = (GenericInstanceMethod)method;
			MethodReference method2 = this.ImportMethod(genericInstanceMethod.ElementMethod, context);
			GenericInstanceMethod genericInstanceMethod2 = new GenericInstanceMethod(method2);
			Collection<TypeReference> genericArguments = genericInstanceMethod.GenericArguments;
			Collection<TypeReference> genericArguments2 = genericInstanceMethod2.GenericArguments;
			for (int i = 0; i < genericArguments.Count; i++)
			{
				genericArguments2.Add(this.ImportType(genericArguments[i], context));
			}
			return genericInstanceMethod2;
		}

		// Token: 0x06000530 RID: 1328 RVA: 0x0001E4BC File Offset: 0x0001C6BC
		public virtual TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
		{
			Mixin.CheckType(type);
			return this.ImportType(type, ImportGenericContext.For(context));
		}

		// Token: 0x06000531 RID: 1329 RVA: 0x0001E4E4 File Offset: 0x0001C6E4
		public virtual FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
		{
			Mixin.CheckField(field);
			return this.ImportField(field, ImportGenericContext.For(context));
		}

		// Token: 0x06000532 RID: 1330 RVA: 0x0001E50C File Offset: 0x0001C70C
		public virtual MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
		{
			Mixin.CheckMethod(method);
			return this.ImportMethod(method, ImportGenericContext.For(context));
		}

		// Token: 0x04000148 RID: 328
		protected readonly ModuleDefinition module;
	}
}
